﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;

namespace Seven.Pool.SignalR
{
    /// <summary>
    /// SignalR服务的自定义Hub类，注意类中方法首字母需要小写，即使大写，在js中调用方法时仍需将方法名首字母改成小写。
    /// </summary>
    public class sevenHub : Hub<IClient>
    {
        public IHubContext CurrentHub { get { return GlobalHost.ConnectionManager.GetHubContext<sevenHub>(); } }

        #region 生命周期事件

        public override Task OnConnected()
        {
            // Add your own code here.
            // For example: in a chat application, record the association between
            // the current connection ID and user name, and mark the user as online.
            // After the code in this method completes, the client is informed that
            // the connection is established; for example, in a JavaScript client,
            // the start().done callback is executed.
            return base.OnConnected();
        }

        public override Task OnDisconnected(bool stopCalled)
        {
            // Add your own code here.
            // For example: in a chat application, mark the user as offline, 
            // delete the association between the current connection id and user name.
            return base.OnDisconnected(stopCalled);
        }

        public override Task OnReconnected()
        {
            // Add your own code here.
            // For example: in a chat application, you might have marked the
            // user as offline after a period of inactivity; in that case 
            // mark the user as online again.
            return base.OnReconnected();
        }

        #endregion

        #region 注册用户连接

        /// <summary>
        /// 注册用户连接
        /// 本方法只能在【前台】被调用
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="userToken">在用户池中的TokenGuid</param>
        /// <param name="groupName">分组名</param>
        public void registeUserConnect(string userName, string userToken, string groupName = "")
        {
            string temp = userName;
            if (!string.IsNullOrWhiteSpace(temp))
            {
                string currentConnectionId = Context.ConnectionId;

                if (temp == Config.SignalRAdminAccount && groupName == Config.SignalRAdminGroup)
                {
                    // 服务池超管，不加入服务池，只需signalr连接存在即可
                    if (!string.IsNullOrWhiteSpace(MemberClient.AdminConnectionID) && !string.IsNullOrWhiteSpace(groupName))
                    {
                        Groups.Remove(MemberClient.AdminConnectionID, groupName);
                    }
                    MemberClient.AdminConnectionID = currentConnectionId;
                }
                else
                {
                    Guid g = Guid.Empty;
                    Guid.TryParse(userToken, out g);
                    Guid k = Guid.Empty;
                    Guid.TryParse(currentConnectionId, out k);
                    MemberClient.AddConnection(temp, g, groupName, k);
                }

                if (!string.IsNullOrWhiteSpace(groupName))
                {
                    Groups.Add(currentConnectionId, groupName);
                }

                string message = "，欢迎您！";
                Clients.Caller.getWelcomeInfo(message, currentConnectionId);

                message = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "&nbsp;&nbsp;【" + temp + "】连接成功，所在分组为【" + groupName + "】";
                pushInfoToAdmin(message, true);
            }
        }

        #endregion

        #region 移除用户连接

        #region 移除 指定用户 的连接

        /// <summary>
        /// 移除指定分组中指定用户名的连接，若存在多处，则移除所有
        /// </summary>
        /// <param name="userName">目标用户名</param>
        /// <param name="groupName">分组名</param>
        /// <param name="jscall">是否js端调用</param>
        public void removeConnectSingleByUserName(string userName, string groupName, bool jscall = false)
        {
            if (!string.IsNullOrWhiteSpace(userName))
            {
                var SpecialConnectKeys = MemberClient.GetTokenGuid(userName, groupName).ToList();

                if (jscall) { Clients.Clients(SpecialConnectKeys).getWelcomeInfo("已下线！"); }
                else { CurrentHub.Clients.Clients(SpecialConnectKeys).getWelcomeInfo("已下线！"); }

                pushInfoToAdmin(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "&nbsp;&nbsp;【" + userName + "】注销下线，所在分组为【" + groupName + "】", jscall);

                MemberClient.RemoveConnection(userName, groupName);

                if (jscall) { Clients.Clients(SpecialConnectKeys).stopClient(); }
                else { CurrentHub.Clients.Clients(SpecialConnectKeys).stopClient(); }
            }
        }

        /// <summary>
        /// 根据连接ID移除连接
        /// </summary>
        /// <param name="connectId">连接id</param>
        /// <param name="jscall">是否js端调用</param>
        public void removeConnectSingleByConnectId(string connectId, bool jscall = false)
        {
            if (!string.IsNullOrWhiteSpace(connectId))
            {
                if (jscall) { Clients.Client(connectId).getWelcomeInfo("已下线！"); }
                else { CurrentHub.Clients.Client(connectId).getWelcomeInfo("已下线！"); }

                Guid g = Guid.Empty;
                Guid.TryParse(connectId, out g);
                MemberToken token = MemberClient.GetToken(g);
                var userName = token.UserName;
                var groupName = token.GroupName;

                pushInfoToAdmin(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "&nbsp;&nbsp;【" + userName + "】注销下线，所在分组为【" + groupName + "】", jscall);

                MemberClient.RemoveConnection(g);

                if (jscall) { Clients.Client(connectId).stopClient(); }
                else { CurrentHub.Clients.Client(connectId).stopClient(); }
            }
        }

        #endregion

        /// <summary>
        /// 移除所有连接
        /// </summary>
        /// <param name="jscall">是否js端调用</param>
        public void removeAllConnect(bool jscall = false)
        {
            if (jscall) { Clients.All.getWelcomeInfo("已下线！"); }
            else { CurrentHub.Clients.All.getWelcomeInfo("已下线！"); }

            pushInfoToAdmin("移除所有连接用户！");

            MemberClient.ClearMemberPool();

            if (jscall) { Clients.All.stopClient(); }
            else { CurrentHub.Clients.All.stopClient(); }
        }

        #endregion

        #region 推送信息

        /// <summary>
        /// 向所有人推送指定信息
        /// 本方法可以【前台/后台】被调用，由参数jscall控制
        /// </summary>
        /// <param name="sender">推送人用户名</param>
        /// <param name="message">推送信息</param>
        /// <param name="jscall">是否js端调用</param>
        public void pushInfoToEveryone(string sender, string message, bool jscall = false)
        {
            if (jscall)
            { Clients.All.getPublicInfo(sender, message); }
            else
            { CurrentHub.Clients.All.getPublicInfo(sender, message); }
        }

        /// <summary>
        /// 在前台执行向指定的连接IDs推送指定信息
        /// </summary>
        /// <param name="sender">信息发送人userName</param>
        /// <param name="receivers">信息接收人的连接ID集合，以英文逗号相连</param>
        /// <param name="message">信息</param>
        public void pushInfoFromJs(string sender, string receivers, string message)
        {
            var special = receivers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            Clients.Clients(special).getPushInfo(sender, message);
        }

        /// <summary>
        /// 向SignalR服务池的超级管理员推送指定信息
        /// </summary>
        /// <param name="message">信息</param>
        /// <param name="jscall">是否js端调用</param>
        public void pushInfoToAdmin(string message, bool jscall = false)
        {
            if (string.IsNullOrWhiteSpace(MemberClient.AdminConnectionID)) { return; }

            if (jscall) { Clients.Client(MemberClient.AdminConnectionID).getActionRecord(message); }
            else { CurrentHub.Clients.Client(MemberClient.AdminConnectionID).getActionRecord(message); }
        }

        #endregion
    }

    /// <summary>
    /// 客户端方法接口，方法名首字母请小写
    /// </summary>
    public interface IClient
    {
        /// <summary>
        /// 显示欢迎信息
        /// </summary>
        /// <param name="message">欢迎信息</param>
        /// <param name="connectedId">连接ID</param>
        void getWelcomeInfo(string message, string connectedId = "");

        /// <summary>
        /// 显示记录信息
        /// </summary>
        /// <param name="info">信息</param>
        void getActionRecord(string info);

        /// <summary>
        /// 显示公共信息
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="message">信息</param>
        void getPublicInfo(string sender, string message);

        /// <summary>
        /// 显示推送信息
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="message">信息</param>
        void getPushInfo(string sender, string message);

        /// <summary>
        /// 重载服务数据
        /// </summary>
        void reloadServiceData();

        /// <summary>
        /// 客户端断开连接
        /// </summary>
        void stopClient();
    }
}